#include "stdafx.h"
#include ".\polygon.h"
#include ".\GDIUtils.h"
#include "color.h"
//#include "DTriangle.h"
#include "GLAddon\Utility.h"

// some global variables
double			g_fSplineSampleError	= 10;	// the sampling error for spline curve

BOOL			g_bPolygonFilled = TRUE;
BOOL			g_bPolygonLined	 = TRUE;
CPoint			g_Origin		 = CPoint(50,650);
int				g_nNumColorEdges = 10;

extern		ColornameElem		ColornameTable[];


// colors of drawing different elements
COLORREF	g_Colors[DHC_SIZE] =
{
	RGB(245,255,255),		// DHC_BKGROUND: color of background
	RGB(0,0,150),			// DHC_LOGCOLOR: color of the log
	RGB(255,0,0),			// DHC_VERTEX: color of drawing vertices of the polygon
	RGB(0,0,255),			// DHC_SELECTED_VERTEX: color of selected vertex in MODIFY operation
	RGB(0,0,255),			// DHC_SELECTED_POLYGON: color of the edges of selected polygons
	RGB(0,255,0),			// DHC_HANDLES: color of the handles of polygon
	RGB(255,0,255),			// DHC_ANCHOR: color of the anchor of polygon
	RGB(100,250,20),		// DHC_BOUNDINGBOX: color of the bounding box of polygon
	RGB(0,100,250),			// DHC_NEWINPUTPOLYGON: color of the edges of new input polygon
	RGB(0,50,50),			// DHC_GRIDLINE: color of the grid lines
	RGB(0,0,0),				// DHC_RUBBER: color of the rubber lines
	RGB(200,250,250),		// DHC_FILLCOLOR: color of the closed polygon filling
	RGB(0,0,0),				// DHC_EDGECOLOR: color of the polygon' edges
	RGB(200,50,200)			// DHC_AXIS: color of the axis
};

// sizes of drawing different elements
unsigned int	g_Sizes[DHC_SIZE] =
{
	0,			// DHC_BKGROUND: no use here...
	11,			// DHC_LOGCOLOR: width of the font
	2,			// DHC_VERTEX: point size of drawing vertices of the polygon
	3,			// DHC_SELECTED_VERTEX: point size of selected vertex in MODIFY operation
	2,			// DHC_SELECTED_POLYGON: line width of the edges of selected polygons
	3,			// DHC_HANDLES: point size of the handles of polygon
	4,			// DHC_ANCHOR: point size of the anchor of polygon
	1,			// DHC_BOUNDINGBOX: line width of the bounding box of polygon
	3,			// DHC_NEWINPUTPOLYGON: line width of the edges of new input polygon
	1,			// DHC_GRIDLINE: line width of the grid lines
	1,			// DHC_RUBBER: line width of the rubber lines
	0,			// DHC_FILLCOLOR:  no use here...
	1,			// DHC_EDGECOLOR:  line width for drawing the polyon's boundary edges
	4			// DHC_AXIS:  line width of axis
};



///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////

CPolygon::CPolygon(void)
{
	m_bClosed = false;

	m_bFilled = g_bPolygonFilled;
	m_FillColor = g_Colors[DHC_FILLCOLOR];

	m_bLined = g_bPolygonLined;	
	m_LineColor = g_Colors[DHC_EDGECOLOR];
	m_nLineWidth = g_Sizes[DHC_EDGECOLOR];
}

CPolygon::~CPolygon(void)
{
	Clear();
}

void	CPolygon::Clear()
{
	m_bClosed = false;
	for (int i = 0; i < (int)m_vecVertex.size(); i++)
	{
		if (m_vecVertex[i] != NULL)
		{
			delete m_vecVertex[i];
			m_vecVertex[i] = NULL;
		}
	}
	m_vecVertex.clear();
}


CPolygon::CPolygon(CPolygon &polygon)
{
	for (int i = 0; i < polygon.NumVertex(); i++)
	{
		CVertex *v = new CVertex(polygon[i]);
		m_vecVertex.push_back(v);
	}
	m_bClosed = polygon.GetClosed();
	VertexNormal();
}


// polygon assignment operation
CPolygon& CPolygon::operator = (CPolygon &polygon)
{
	Clear();

	for (int i = 0; i < polygon.NumVertex(); i++)
	{
		CVertex *v = new CVertex(polygon[i]);
		m_vecVertex.push_back(v);
	}
	m_bClosed = polygon.m_bClosed;

	return *this;
}

CVertex& CPolygon::operator[](int index)
{
	return *m_vecVertex[index];
}

vertex_list& CPolygon::GetVertexList()
{
	return m_vecVertex;
}


// assign a vertex list to the polygon, but how is "m_bClosed" -- should call the procedure SetClosed() etc....
void CPolygon::Assign(vertex_list &list)
{
	Clear();
	m_vecVertex.assign(list.begin(), list.end());
}

// return the number of vertices
int CPolygon::NumVertex() 
{ 
	return (int)m_vecVertex.size();
};

// judge whether this polygon is closed or not
bool CPolygon::GetClosed() 
{ 
	assert(m_vecVertex.size() > 0);

	return m_bClosed;
}

// set the polyline to be closed
void CPolygon::SetClosed()
{
	SetClosed( true );
}


void CPolygon::SetClosed(bool close)
{
	m_bClosed = close;
}

void CPolygon::SetNonClosed()
{
	SetClosed( false );
}

// remove a vertex at index
void CPolygon::RemoveAt( int index )
{
	CVertex *pVert = m_vecVertex[ index ];
	m_vecVertex.erase( m_vecVertex.begin() + index );
	if( pVert )
	{
		delete pVert;
		pVert = NULL ;
	}
}

void CPolygon::RemoveLast()
{
	RemoveAt( NumVertex()-1 );
}

// insert a vertex at index
void CPolygon::InsertAt( int index, CVertex *pV )
{
	m_vecVertex.insert( m_vecVertex.begin() + index, pV );
}

// add a new vertex at the end of the vertex list
void CPolygon::AddVertex(CVertex *CVertex)
{
	m_vecVertex.push_back(CVertex);
}

void CPolygon::AddVertex(double x, double y)
{
	m_vecVertex.push_back( new CVertex(x,y) );
}

void CPolygon::AddVertex(int x, int y)
{
	AddVertex( (double)x, (double)y );
}

// Reverse the vertex of polygon
void CPolygon::Reverse()
{
	vertex_list list;
	int count = static_cast<int>( m_vecVertex.size() );
	for ( int i = ( count - 1 ); i >= 0; i-- )
	{
		CVertex *vertex = m_vecVertex.at( i );
		CVertex *ver = new CVertex( *vertex );
		list.push_back( ver );
	}

	bool close = GetClosed();
	Assign( list );
	//m_vecVertex.swap( list );
	SetClosed( close );
}

// reverse the order of vertex, the same as Reverse(), but simpler
void		CPolygon::ReverseOrientation()
{
	int num = NumVertex();
	int sz = num-1;
	if( GetClosed() )
		sz = num;

	for( int i=0; i<=sz/2; i++ )
	{
		// swap the 2 elements
		CVertex *pV = GetVertex(i);
		m_vecVertex[i] = m_vecVertex[sz-i];
		m_vecVertex[ sz-i ] = pV;
	}
}


// sudivide all edges uniformly
void		CPolygon::SubAllEdge( int nSeg )
{
	if( nSeg<=1 )
		return;

	int num = NumVertex();
	for( int i=0; i<num; i++ )
	{
		int idx = i * nSeg ;
		SubEdge( idx, nSeg );
	}
}


// subdivide an edge uniformly
void		CPolygon::SubEdge( int idx, int nSeg )
{
	if( nSeg<=1 )
		return ;

	int num = NumVertex();
	if( idx == num-1 )
	{
		if( !GetClosed() )
			return ;

		CVertex *pV0 = GetVertex( idx );
		CVertex *pV1 = GetVertex( 0 );
		for( int i=1; i<nSeg; i++ )
		{
			double t = ((double)i)/ nSeg;
			AddVertex( (1-t)*pV0->x + t*pV1->x, (1-t)*pV0->y + t*pV1->y ); // add to the end
		}
	}
	else
	{
		CVertex *pV0 = GetVertex( idx );
		CVertex *pV1 = GetVertex( idx+1 );
		for( int i=nSeg-1; i>=1; i-- )
		{
			double t = ((double)i)/ nSeg;
			InsertAt( idx+1, new CVertex( (1-t)*pV0->x + t*pV1->x, (1-t)*pV0->y + t*pV1->y ) );
		}
	}
}


// save the polygon into a file : for debugging
void CPolygon::Save( const char *fname )
{
	FILE *fp;
	if( (fp = fopen( fname, "wt" )) == NULL ) 
		return;

	Save( fp );
	fclose( fp );
}

void CPolygon::Save( FILE *fp )
{
	fprintf(fp, "\npolygon has %d vertices: \n", (int)m_vecVertex.size() );
	for( int i=0; i < (int)m_vecVertex.size(); i++ )
	{
		CVertex *pVert = m_vecVertex[i];
		fprintf(fp, "%2d : %f %f\n", i, pVert->x, pVert->y );
	}
}


CVertex	*CPolygon::GetVertex(int Index)
{
    if( Index<0 || Index>=NumVertex() )
        return 0;

    return m_vecVertex.at(Index);
}

void		CPolygon::UpdateChanges()
{
	ComputeBoundingBox();
	VertexNormal();
	//ComputeAnchor();
}

void		CPolygon::ComputeHandles()
{
	ComputeBoundingBox();
	ComputeAnchor();
}

// compute anchor point
void		CPolygon::ComputeAnchor()
{
	m_Handles[ POLYHNDL_ANCHOR    ].Set( (XMin()+XMax())/2, (YMin()+YMax())/2 );
}

// compute bounding box
void		CPolygon::ComputeBoundingBox()
{
	double xmin, ymin, xmax, ymax ;
	xmin = ymin = 99999;
	xmax = ymax = -xmin;

	for( int i=0; i<NumVertex(); i++ )
	{
		CVertex *pV = GetVertex( i );
		double x = pV->x;
		double y = pV->y;
		if( x < xmin )	xmin = x;
		if( y < ymin )	ymin = y;
		if( x > xmax )	xmax = x;
		if( y > ymax )	ymax = y;
	}

	double xcen = (xmin+xmax)/2, ycen=(ymin+ymax)/2 ;

	// set all the handles
	m_Handles[ POLYHNDL_UPPERLEFT ].Set( xmin, ymin );
	m_Handles[ POLYHNDL_LEFT      ].Set( xmin, ycen );
	m_Handles[ POLYHNDL_LOWERLEFT ].Set( xmin, ymax );
	m_Handles[ POLYHNDL_BOTTOM    ].Set( xcen, ymax );
	m_Handles[ POLYHNDL_LOWERRIGHT].Set( xmax, ymax );
	m_Handles[ POLYHNDL_RIGHT     ].Set( xmax, ycen );
	m_Handles[ POLYHNDL_UPPERRIGHT].Set( xmax, ymin );
	m_Handles[ POLYHNDL_UPPER     ].Set( xcen, ymin );
}


//-----------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------
// translate
void		CPolygon::Translate( double px, double py )
{
	for( int i=0; i<NumVertex(); i++ )
	{
		CVertex *pV = GetVertex(i);
		pV->x += px;
		pV->y += py;
	}

	TranslateAnchor( px, py );

	UpdateChanges();
}

void		CPolygon::TranslateAnchor( double px, double py )
{
	m_Handles[ POLYHNDL_ANCHOR ].x += px;
	m_Handles[ POLYHNDL_ANCHOR ].y += py;
}


//-----------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------
// shear X
double		CPolygon::GetShearXScale( double x0, double y0, double x1, double y1 )
{
	double yorg = m_Handles[ POLYHNDL_ANCHOR ].y;

	double scale;
	if( fabs( y0 - yorg ) < MINMOVE )
		scale = 0;
	else
		scale = (x1 - x0)/(y0 - yorg );

	return scale ;
}

void		CPolygon::ShearX( double scale, double yorg )
{
	for( int i=0; i<NumVertex(); i++ )
	{
		CVertex *pV = GetVertex(i);
		pV->x = pV->x + scale * (pV->y - yorg) ;
	}

	// recompute anchor
	CVertex *pV = &m_Handles[POLYHNDL_ANCHOR];
	pV->x = pV->x + scale * (pV->y - yorg) ;

	UpdateChanges();
}

void		CPolygon::ShearX( double scale )
{
	ShearX( scale, m_Handles[ POLYHNDL_ANCHOR ].y );
}

void		CPolygon::ShearMoveX( double x0, double y0, double x1, double y1 )
{
	ShearX( GetShearXScale(x0,y0,x1,y1) );
}


//-----------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------
// shear Y
double		CPolygon::GetShearYScale( double x0, double y0, double x1, double y1 )
{
	double xorg = m_Handles[ POLYHNDL_ANCHOR ].x;

	double scale;
	if( fabs( x0 - xorg ) < MINMOVE )
		scale = 0;
	else
		scale = (y1 - y0)/(x0 - xorg );

	return scale;
}

void		CPolygon::ShearY( double scale, double xorg )
{
	for( int i=0; i<NumVertex(); i++ )
	{
		CVertex *pV = GetVertex(i);
		pV->y = pV->y + scale * (pV->x - xorg) ;
	}

	// recompute anchor
	CVertex *pV = &m_Handles[POLYHNDL_ANCHOR];
	pV->y = pV->y + scale * (pV->x - xorg) ;

	UpdateChanges();
}

void		CPolygon::ShearY( double scale )
{
	ShearY( scale, m_Handles[ POLYHNDL_ANCHOR ].x );
}

void		CPolygon::ShearMoveY( double x0, double y0, double x1, double y1 )
{
	ShearY( GetShearYScale(x0,y0,x1,y1 ) );
}


//-----------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------
// rotate
double		CPolygon::GetRotateAngle( double x0, double y0, double x1, double y1 )
{
	CVertex &org = m_Handles[ POLYHNDL_ANCHOR ];
	CVertex v1( x0, y0 );
	CVertex v2( x1, y1 );

	// calculate the rotate angle
	double angle = CGDIUtils::CalcAngle( org, v1, org, v2 );

	return angle;
}

void		CPolygon::RotateMove( double x0, double y0, double x1, double y1 )
{
	Rotate( GetRotateAngle(x0,y0,x1,y1) );
}

void		CPolygon::Rotate( double angle )
{
	double xorg = m_Handles[ POLYHNDL_ANCHOR ].x ;
	double yorg = m_Handles[ POLYHNDL_ANCHOR ].y ;

	Rotate( angle, xorg, yorg);
}

void		CPolygon::Rotate( double angle, double xorg, double yorg )
{
	double cose = cos( angle );
	double sine = sin( angle );

	for( int i=0; i<NumVertex(); i++ )
	{
		CVertex *pV = GetVertex(i);
		double x = pV->x - xorg;
		double y = pV->y - yorg;

		pV->x = cose * x - sine * y + xorg;
		pV->y = sine * x + cose * y + yorg;
	}

	// recompute anchor
	CVertex &vert = m_Handles[POLYHNDL_ANCHOR];
	double x = vert.x - xorg;
	double y = vert.y - yorg;
	vert.x = cose * x - sine * y + xorg;
	vert.y = sine * x + cose * y + yorg;

	UpdateChanges();
}


//-----------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------
// scale X
double		CPolygon::GetScaleXScale( double x0, double x1 )
{
	double xorg = m_Handles[ POLYHNDL_ANCHOR ].x ;
	double scale;
	if( fabs( x0 - xorg ) < MINMOVE )
		scale = 1.0;
	else
		scale = ( x1 - xorg ) / ( x0 - xorg );
	
	return scale;
}

void		CPolygon::ScaleMoveX( double x0, double x1 )
{
	ScaleX( GetScaleXScale(x0,x1) );
}

void		CPolygon::ScaleX( double scale )
{
	ScaleX( scale, m_Handles[ POLYHNDL_ANCHOR ].x );
}

void		CPolygon::ScaleX( double scale, double xorg )
{
	for( int i=0; i<NumVertex(); i++ )
	{
		CVertex *pV = GetVertex( i );
		pV->x = (pV->x - xorg) * scale + xorg;
	}

	// recompute anchor
	CVertex *pV = &m_Handles[POLYHNDL_ANCHOR];
	pV->x = (pV->x - xorg) * scale + xorg;

	UpdateChanges();
}


//-----------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------
// scale Y
double		CPolygon::GetScaleYScale( double y0, double y1 )
{
	double yorg = m_Handles[ POLYHNDL_ANCHOR ].y ;
	double scale;
	if( fabs( y0 - yorg ) < MINMOVE )
		scale = 1.0;
	else
		scale = ( y1 - yorg ) / ( y0 - yorg );

	return scale;
}

void		CPolygon::ScaleMoveY( double y0, double y1 )
{
	ScaleY( GetScaleYScale(y0,y1) );
}

void		CPolygon::ScaleY( double scale )
{
	ScaleY( scale, m_Handles[ POLYHNDL_ANCHOR ].y );
}

void		CPolygon::ScaleY( double scale, double yorg )
{
	for( int i=0; i<NumVertex(); i++ )
	{
		CVertex *pV = GetVertex( i );
		pV->y = (pV->y - yorg) * scale + yorg;
	}

	// recompute anchor
	CVertex *pV = &m_Handles[POLYHNDL_ANCHOR];
	pV->y = (pV->y - yorg) * scale + yorg;

	UpdateChanges();
}


//-----------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------
// scale X and Y
void		CPolygon::Scale( double scaleX, double scaleY )
{
	ScaleX( scaleX );
	ScaleY( scaleY );
}

void		CPolygon::Scale( double scaleX, double scaleY, double xorg, double yorg)
{
	ScaleX( scaleX, xorg );
	ScaleY( scaleY, yorg );
}

void		CPolygon::ScaleMove( double x0, double y0, double x1, double y1 )
{
	double xorg = m_Handles[ POLYHNDL_ANCHOR ].x ;
	double yorg = m_Handles[ POLYHNDL_ANCHOR ].y ;

	double scaleX = GetScaleXScale(x0, x1);
	double scaleY = GetScaleYScale(y0, y1);

	Scale( scaleX, scaleY, xorg, yorg );
}

void		CPolygon::ScaleMoveUnified( double x0, double y0, double x1, double y1 )
{
	double xorg = m_Handles[ POLYHNDL_ANCHOR ].x ;
	double yorg = m_Handles[ POLYHNDL_ANCHOR ].y ;

	double scaleX = GetScaleXScale(x0, x1);
	double scaleY = GetScaleYScale(y0, y1);

	double scale = (scaleX<scaleY) ? scaleX : scaleY;

	Scale( scale, scale, xorg, yorg );
}

//-----------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------
// flip
void		CPolygon::FlipVertical( double ybase )
{
	for( int i=0; i<NumVertex(); i++ )
	{
		CVertex *pV = GetVertex(i);
		pV->y = 2*ybase - pV->y;
	}

	// recompute anchor
	CVertex *pV = &m_Handles[POLYHNDL_ANCHOR];
	pV->y = 2*ybase - pV->y;

	UpdateChanges();

	ReverseOrientation();
}

void		CPolygon::FlipVertical()
{
	FlipVertical( m_Handles[ POLYHNDL_ANCHOR ].y );
}

void		CPolygon::FlipHorizontal( double xbase )
{
	for( int i=0; i<NumVertex(); i++ )
	{
		CVertex *pV = GetVertex(i);
		pV->x = 2*xbase - pV->x;
	}

	// recompute anchor
	CVertex *pV = &m_Handles[POLYHNDL_ANCHOR];
	pV->x = 2*xbase - pV->x;

	UpdateChanges();

	ReverseOrientation();
}

void		CPolygon::FlipHorizontal()
{
	FlipHorizontal( m_Handles[ POLYHNDL_ANCHOR ].x );
}


//-----------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------

HandleMode	CPolygon::PointHandleMode( double px, double py )
{
	if( NumVertex() == 1 )
	{
		if( CGDIUtils::PointInPoint( px, py, GetVertex(0)->x, GetVertex(0)->y ) )
			return POLYHNDL_INSIDE;
		else if( CGDIUtils::PointInPoint( px, py, m_Handles[ POLYHNDL_ANCHOR ].x, m_Handles[ POLYHNDL_ANCHOR ].y ) )
			return POLYHNDL_ANCHOR;
		else
			return POLYHNDL_OUTSIDE;
	}

	// for very small objects
	int nSmallSize = 10;
	if( XMax()-XMin() < nSmallSize && YMax() - YMin() < nSmallSize && PolyContainPoint( px, py ) )
		return POLYHNDL_INSIDE;

	for( int mode=POLYHNDL_UPPERLEFT; mode<POLYHNDL_NUMBER; mode++ )
	{
		CVertex &vert = m_Handles[ mode ];
		if( CGDIUtils::PointInPoint( px, py, vert.x, vert.y  ) )
		{
			return (HandleMode)mode;
		}
	}

	if( PolyContainPoint( px, py ) )
		return POLYHNDL_INSIDE;
	else
		return POLYHNDL_OUTSIDE;
}

CVertex		CPolygon::GetHandle( HandleMode mode )
{
	assert( mode >=0 && mode<POLYHNDL_NUMBER );
	return m_Handles[mode];
}

int		CPolygon::PolyVertexOnEdge( double &ratio, double px, double py )
{
	int nSize = NumVertex();
	if( nSize < 2 )
		return -1;

	int nS = nSize;
	if( !GetClosed() )
		nSize--;

	for( int i=0; i<nSize; i++ )
	{
		CVertex *pV0 = GetVertex(i);
		CVertex *pV1 = GetVertex((i+1)%nS);
		if( CGDIUtils::PointOnLine( px, py, pV0->x, pV0->y, pV1->x, pV1->y, ratio ) )
			return i;
	}

	return -1;
}

CPolygon	*CPolygon::Clone()
{
	CPolygon *newPoly = new CPolygon();

	// copy the vertex list
	vertex_list &vls = newPoly->GetVertexList();
	for( int i=0; i<NumVertex(); i++ )
	{
		CVertex *pV = new CVertex( *GetVertex(i) );
		vls.push_back( pV );
	}

	// set close flag
	newPoly->SetClosed( GetClosed() );

	// set filled flags
	newPoly->SetFilled( GetFilled() );
	newPoly->SetFilledColor( GetFilledColor() );

	// line flags
	newPoly->SetLined( GetLined() );
	newPoly->SetLineWidth( GetLineWidth() );
	newPoly->SetLinedColor( GetLinedColor() );

	// copy the handles
	for( int i=0; i<POLYHNDL_NUMBER; i++ )
	{
		newPoly->m_Handles[i] = GetHandle((HandleMode)i);
	}

	return newPoly;
}


void		CPolygon::Zoom( double ratio )
{
	// compute the vertices
	for( int i=0; i<NumVertex(); i++ )
	{
		CVertex *pV = GetVertex(i);
		pV->Set( pV->x * ratio, pV->y * ratio );
	}

	// compute the handles
	for( int i=0; i<POLYHNDL_NUMBER; i++ )
	{
		CVertex &pV = m_Handles[i];
		pV.Set( pV.x * ratio, pV.y * ratio );
	}
}


// resmaple the polygon by nNumVertices, and compute the tangent vectors of each vertex
void		CPolygon::Resample( int nNumVertices, BOOL bKeepOrgVertices )
{
	nNumVertices--;
	bool close = GetClosed();

	double totallength = 0;
	std::vector<double>	edgelengths;
	edgelengths.push_back(0);
	int numvert = NumVertex();
	if( close )		// for closed polygon
		numvert++;

	for( int i=1; i<numvert; i++ )
	{
		CVertex *pV0 = GetVertex(i-1);
		CVertex *pV1 = GetVertex(i%NumVertex());
		double length = CGDIUtils::Distance( *pV0, *pV1 );
		totallength += length;
		edgelengths.push_back( totallength );
	}

	// normalize into [0,1]
	assert( numvert == edgelengths.size() );
	for( int i=0; i<numvert; i++ )
	{
		edgelengths[i] /= totallength;
	}

	if( close )
		nNumVertices++;

	if( !bKeepOrgVertices )
	{
		vertex_list newverts;
		for( int i=0; i<=nNumVertices; i++ )
		{
			double t = (double)i / (double)nNumVertices;
			int pos = 0;
			while( pos < numvert && t >= edgelengths[pos] )
			{
				pos++ ;
			}

			pos--;

			CVertex *pV0 = GetVertex( pos%NumVertex() );
			CVertex *pV1 = GetVertex( (pos+1)%NumVertex() );
			t = ( t - edgelengths[pos] )/(edgelengths[(pos+1)%numvert]-edgelengths[pos%numvert]);
			double x = (1-t)*pV0->x + t*pV1->x;
			double y = (1-t)*pV0->y + t*pV1->y;
			newverts.push_back( new CVertex(x,y) );
		}

		if( close )	// remove the last one
		{
			int last = (int)newverts.size() - 1;
			delete newverts[last];
			newverts.erase( newverts.begin() + last );
		}

		Assign( newverts );
		SetClosed( close );
	}
	else
	{
		// to do...
	}

	UpdateChanges();
}


// reset vertex order from the idx vertex
void		CPolygon::ResetOrder( int idx )
{
	// can not reset order for non-closed polygon
	if( !GetClosed() )
		return ;

	int num = NumVertex();
	vertex_list templs;
	for( int i=0; i<num; i++ )
	{
		templs.push_back( this->GetVertex(i) );
	}

	for( int i=0; i<num; i++ )
	{
		m_vecVertex[i] = templs[ (i+idx)%num ];
	}
}

// set anchor to be some vertex
void	CPolygon::SetAnchor( int idx )
{
	CVertex *pV = GetVertex( idx );
	m_Handles[ POLYHNDL_ANCHOR ].Set( pV->x, pV->y );
}

void	CPolygon::SetAnchorAsFirstVertex()
{
	SetAnchor(0);
}

void	CPolygon::SetAnchor( double x, double y )
{
	m_Handles[ POLYHNDL_ANCHOR ].Set( x, y );
}

void	CPolygon::SetAnchorAsCenter()
{
	CVertex pt1 = m_Handles[ POLYHNDL_UPPERLEFT ];
	CVertex pt2 = m_Handles[ POLYHNDL_LOWERRIGHT ];
	SetAnchor( (pt1.x+pt2.x)/2, (pt1.y+pt2.y)/2 );
}

void	CPolygon::SetAnchorAsHandle(HandleMode mode)
{
	assert( mode>=0 && mode<POLYHNDL_ANCHOR );
	SetAnchor(m_Handles[ mode ].x, m_Handles[ mode ].y);
}

// split the polygon into 2 at some index
CPolygon	*CPolygon::Split( int idx )
{
	int num = NumVertex();
	if( !GetClosed() )	// for non-closed polygon, it is splitted into 2 polygons
	{
		if(idx == 0 || idx == num-1)
			return NULL;

		CPolygon *pNewPoly = new CPolygon;
		
		// generate the new poly
		// the vertex at idx should be copied
		CVertex *pV = new CVertex( *(GetVertex(idx)) );
		pNewPoly->AddVertex( pV );
		for( int i=idx+1; i<num; i++ )
		{
			pNewPoly->AddVertex( GetVertex(i) );
		}

		// modify the old poly
		for( int i=num-1; i>=idx+1; i-- )
		{
			m_vecVertex.erase( m_vecVertex.begin() + i );
		}

		// update the handle informations
		pNewPoly->SetClosed( false );
		pNewPoly->ComputeHandles();
		this->ComputeHandles();

		return pNewPoly;
	}
	else	// for closed polygon, it is made non-closed at the vertex
	{
		vertex_list templs;
		for( int i=0; i<num; i++ )
		{
			templs.push_back( this->GetVertex(i) );
		}

		for( int i=0; i<num; i++ )
		{
			m_vecVertex[i] = templs[ (i+idx)%num ];
		}

		// add the new vertex
		CVertex *pV = this->GetVertex(0);
		CVertex *pNewVertex = new CVertex( pV->x, pV->y );
		AddVertex( pNewVertex );

		SetClosed( false );
		return NULL;
	}
}


int		CPolygon::PolyVertexOnPoint( double px, double py )
{
	for( int i=0; i<NumVertex(); i++ )
	{
		CVertex *pV = GetVertex(i);
		if( CGDIUtils::PointInPoint( px, py, pV->x, pV->y ) )
			return i;
	}

	return -1;
}

int		CPolygon::PolyContainPoint( double px, double py )
{
	int ok = FALSE;

	// if it is the handle points
	for( int i=0; i<POLYHNDL_NUMBER; i++ )
	{
		if( CGDIUtils::PointInPoint( px, py, m_Handles[i].x, m_Handles[i].y ) )
			return TRUE;
	}

	int nSize = NumVertex();
	assert( nSize > 0 );
	if( GetClosed() && nSize >= 3 )
	{
		CRgn rgn;
		CPoint *ptPnts = new CPoint[ nSize ];
		for( int i=0; i<nSize; i++ )
		{
			CVertex *pV = GetVertex(i);
			ptPnts[i].x = (int)pV->x;
			ptPnts[i].y = (int)pV->y;
		}

		rgn.CreatePolygonRgn( ptPnts, nSize, ALTERNATE );
		ok = rgn.PtInRegion( (int)px, (int)py );

		delete ptPnts;
	}
	else	// non-closed polygon
	{
		if( nSize == 1 )
		{
			CVertex *pV0 = GetVertex(0);
			return CGDIUtils::PointInPoint(px, py, pV0->x, pV0->y);
		}
		else
		{
			for( int i=0; i<nSize-1; i++ )
			{
				CVertex *pV0 = GetVertex(i);
				CVertex *pV1 = GetVertex(i+1);
				double ratio;
				if( CGDIUtils::PointOnLine(px, py, pV0->x, pV0->y, pV1->x, pV1->y, ratio) )
				{ 
					ok = TRUE ;
					break;
				}
			}
		}
	}

	return ok;
}

/*
// drawing procedures
void	CPolygon::Draw( CDC *pDC )
{
	int num = NumVertex();
	if( num == 0 ) 
		return ;

	CPoint *pPt = new CPoint[num];

	for( int i=0; i<num; i++ )
	{
		CVertex *pV = GetVertex( i );
		pPt[i].x = (int)pV->x;
		pPt[i].y = (int)pV->y;
	}

	// line drawing setting
	CPen	pen( PS_SOLID, m_nLineWidth, m_LineColor );
	CGDISelectObject<CPen>		tmpPen(pDC, &pen);
	if( !GetLined() )
	{
		pDC->SelectStockObject( NULL_PEN );
	}


	// fill drawing setting
	if( !m_bClosed )
		pDC->Polyline( pPt, num );
	else	// closed polyogn
	{
		CBrush  brush( m_FillColor );
		CGDISelectObject<CBrush>		tmpBrush(pDC, &brush);
		if( !GetFilled() )
		{
			pDC->SelectStockObject( NULL_BRUSH );
		}

		pDC->Polygon( pPt, num );
	}

	delete pPt;
}
*/

// draw the polygon using preset pen, almost is the same as Draw()
void	CPolygon::Draw( CDC *pDC, CPen *psetpen )
{
	int num = NumVertex();
	if( num == 0 ) 
		return ;

	CPoint *pPt = new CPoint[num];

	for( int i=0; i<num; i++ )
	{
		CVertex *pV = GetVertex( i );
		pPt[i].x = (int)pV->x;
		pPt[i].y = (int)pV->y;
	}

	// line drawing setting
	CGDISelectObject<CPen>		tmpPen( pDC, psetpen );
	CPen pen( PS_SOLID, m_nLineWidth, m_LineColor );
	if( psetpen == NULL )
	{
		tmpPen.Set( pDC, &pen );

		if( !GetLined() )
		{
			pDC->SelectStockObject( NULL_PEN );
		}
	}


	// fill drawing setting
	if( !m_bClosed )
		pDC->Polyline( pPt, num );
	else	// closed polyogn
	{
		CBrush  brush( m_FillColor );
		CGDISelectObject<CBrush>		tmpBrush(pDC, &brush);
		if( !GetFilled() )
		{
			pDC->SelectStockObject( NULL_BRUSH );
		}

		pDC->Polygon( pPt, num );
	}

	delete pPt;
}


void	CPolygon::Draw( CDC *pDC, BOOL bColoredEdge )
{
	int num = NumVertex();
	if( num == 0 ) 
		return ;

	int nSmallSize = 10;
	if( !bColoredEdge || (XMax()-XMin() < nSmallSize && YMax() - YMin() < nSmallSize) )
	{
		Draw( pDC );
	}
	else
	{
		CPoint *pPt = new CPoint[num];

		for( int i=0; i<num; i++ )
		{
			CVertex *pV = GetVertex( i );
			pPt[i].x = (int)pV->x;
			pPt[i].y = (int)pV->y;
		}

		// filling first
		if( m_bClosed )
		{
			// fill drawing setting
			CBrush  brush( m_FillColor );
			CGDISelectObject<CBrush>		tmpBrush(pDC, &brush);
			if( !GetFilled() )
			{
				pDC->SelectStockObject( NULL_BRUSH );
			}

			pDC->Polygon( pPt, num );
		}

		// draw segment-based colored edges every 10 points
		int idx = 0;
		
		COLORREF color;
		color = RGB(ColornameTable[idx].red, ColornameTable[idx].green, ColornameTable[idx].blue) ;
		for( int i=1; i<num; i++ )
		{
			CGDIUtils::DrawLine(pDC, pPt[i-1], pPt[i], color );

			if( i%g_nNumColorEdges == 0 )
			{
				idx++;
				color = RGB(ColornameTable[idx].red, ColornameTable[idx].green, ColornameTable[idx].blue) ;
			}
		}

		if( m_bClosed )
		{
			CGDIUtils::DrawLine(pDC, pPt[0], pPt[num-1], color );
		}

		delete pPt;
	}
}

// draw the vertices in red color
void	CPolygon::DrawVertices( CDC *pDC )
{
    for(int Index=0; Index<NumVertex(); Index++)
    {
        CVertex *pV = GetVertex(Index);
		CGDIUtils::DrawFilledBox( pDC, CPoint( (int)pV->x, (int)pV->y ), g_Sizes[DHC_VERTEX], g_Colors[DHC_VERTEX] );
	}
}

void	CPolygon::DrawVerticesInGL()
{
	for(int Index=0; Index<NumVertex(); Index++)
	{
	}
}

// show vertex indices
void	CPolygon::ShowVertexIndices( CDC *pDC )
{
	CGDISetBkMode tmp( pDC, TRANSPARENT );
    for(int Index=0; Index<NumVertex(); Index++)
    {
        CVertex *pV = GetVertex(Index);

		char ch[128];
		sprintf( ch, "%d", Index );
		pDC->TextOut( (int)pV->x, (int)pV->y, ch );
	}
}


void		CPolygon::DrawBoundingBox( CDC *pDC )
{
	CPen pen( PS_SOLID, g_Sizes[DHC_BOUNDINGBOX], g_Colors[DHC_BOUNDINGBOX] );
	CGDISelectObject<CPen> tmpPen(pDC, &pen);

	int xmin = (int)(XMin()), ymin = (int)(YMin()), xmax = (int)(XMax()), ymax = (int)(YMax());
	pDC->MoveTo( xmin, ymin );
	pDC->LineTo( xmin, ymax );
	pDC->LineTo( xmax, ymax );
	pDC->LineTo( xmax, ymin );
	pDC->LineTo( xmin, ymin );
}

void		CPolygon::DrawHandles( CDC *pDC )
{
	// draw bounding box
	DrawBoundingBox( pDC );

	// draw anchor
	CVertex &vert = m_Handles[ POLYHNDL_ANCHOR ];
	CGDIUtils::DrawFilledCircle( pDC, CPoint( (int)vert.x, (int)vert.y ), g_Sizes[DHC_ANCHOR], g_Colors[DHC_ANCHOR] );

	// draw other handles
	for( int i=0; i<POLYHNDL_NUMBER; i++ )
	{
		if( i==POLYHNDL_ANCHOR )
			continue ;

		CVertex &vert = m_Handles[ i ];
		CGDIUtils::DrawFilledBox( pDC, CPoint( (int)vert.x, (int)vert.y ), g_Sizes[DHC_HANDLES], g_Colors[DHC_HANDLES] );
	}
}


// void CPolygon::DelaunayTriangulation( CString fname,double transX/*=0*/, double flipY/*=0*/,double AvgTriArea/*=100.0*/,bool bAddFrameBorder/*=false*/, float frameWidth/*=0.0*/, float frameHeight/*=0.0*/ )
// {
// // 	Translate( -g_Origin.x, 0 );
// // 	FlipVertical( g_Origin.y / 2 );
// // 	ReverseOrientation();
// 
// 
// 	struct triangulateio in, out;
// 
// 	// number of the polygon vertices
// 	int VertexCount = NumVertex();
// 	// vertices list
// 	vertex_list PolygonVertexList = GetVertexList();
// 	if(!bAddFrameBorder){
// 		// set points and segments for "in"
// 		in.numberofpoints = VertexCount;
// 		in.numberofsegments = VertexCount;
// 		in.pointlist = (Real *) malloc( ( in.numberofpoints ) * 2 * sizeof(Real));
// 		in.segmentlist = (int *)malloc( in.numberofsegments * 2 * sizeof( int ) );
// 		for ( int i = 0; i < VertexCount; i++ )
// 		{
// 			CVertex *vertex = PolygonVertexList.at( i );
// 			in.pointlist[2*i] = vertex->x + transX;
// 			in.pointlist[2*i+1] = flipY - vertex->y;
// 			in.segmentlist[2*i] = i;
// 			in.segmentlist[2*i+1] = i + 1;
// 		}
// 		in.segmentlist[2*VertexCount-1] = 0; //made close
// 	}
// 	else{
// 		in.numberofpoints = VertexCount+4;
// 		in.numberofsegments = VertexCount+4;
// 		in.pointlist = (Real *) malloc( ( in.numberofpoints ) * 2 * sizeof(Real));
// 		in.segmentlist = (int *)malloc( in.numberofsegments * 2 * sizeof( int ) );
// 		for ( int i = 0; i < VertexCount; i++ )
// 		{
// 			CVertex *vertex = PolygonVertexList.at( i );
// 			in.pointlist[2*i] = vertex->x + transX;
// 			in.pointlist[2*i+1] = flipY - vertex->y;
// 			in.segmentlist[2*i] = i;
// 			in.segmentlist[2*i+1] = i + 1;
// 		}
// 		in.segmentlist[2*VertexCount-1] = 0;  //made close
// 
// 		in.pointlist[(VertexCount+0)*2]	= 0;			in.pointlist[(VertexCount+0)*2+1] = flipY - frameHeight;
// 		in.pointlist[(VertexCount+1)*2]	= frameWidth;	in.pointlist[(VertexCount+1)*2+1] = flipY - frameHeight;
// 		in.pointlist[(VertexCount+2)*2]	= frameWidth;	in.pointlist[(VertexCount+2)*2+1] = flipY;
// 		in.pointlist[(VertexCount+3)*2]	= 0;			in.pointlist[(VertexCount+3)*2+1] = flipY;
// 		for (unsigned j=0; j<4; ++j){
// 			in.segmentlist[2*VertexCount+j*2]	= VertexCount+j%4;			
// 			in.segmentlist[2*VertexCount+j*2+1] = VertexCount+(j+1)%4;
// 		}
// 	}
// 
// 	// perform Delaunay triangulation for "in" polygon, do not make the Voronoi diagram
// 	//report(&in, 1, 0, 0, 0, 0, 0);	// how to show the informations for "in" and "out"
// 	//triangulate("pzL", &in, &out,(struct triangulateio *) NULL); // just for Delaunay triangulation
// 	CString cmd("pzLa");
// 	CString arStr;  arStr.Format("%0.9f", AvgTriArea);
// 	cmd = cmd+arStr;
// 	std::cout<<"delaunay triangulation command : "<<cmd<<"\n"; 
// 	triangulate(cmd.GetBuffer(), &in, &out,(struct triangulateio *) NULL);
// 	//report(&out, 1, 1, 1, 1, 1, 0);
// 
// 
// 	// output the Delaulay triangulation of a polygon
// 
// 	FILE *fp;	
// 	fname+=".obj";	
// 	fp = fopen(fname, "wt") ;
// 
// 	// output the number of vertices and triangles
// 	//fprintf(fp, "# vertices: %d  triangles: %d\n", PolygonVertexList.size(), out.numberoftriangles );
// 	fprintf(fp, "# vertices: %d  triangles: %d\n", out.numberofpoints, out.numberoftriangles );
// 
// 	// output the vertices
// 	// the following are for Delaunay triangulation
// 	//assert(PolygonVertexList.size() == out.numberofpoints);
// 	//for( int i=0; i<(int)PolygonVertexList.size(); i++ )
// 	//{
// 	//	CVertex *pV = PolygonVertexList.at( i );
// 	//	fprintf( fp, "v %f %f 0.0\n", pV->x, pV->y );
// 	//}
// 	for( int i=0; i<out.numberofpoints; i++ )
// 	{
// 		double xx = out.pointlist[2*i+0];
// 		double yy = out.pointlist[2*i+1];
// 		fprintf( fp, "v %f %f 0.0\n", xx, yy );
// 	}
// 
// 	for ( int i = 0; i < out.numberoftriangles; i++ )
// 	{
// 		// generate triangle list
// 		int VertexIndex0 = out.trianglelist[3*i];
// 		int VertexIndex1 = out.trianglelist[3*i+1];
// 		int VertexIndex2 = out.trianglelist[3*i+2];
// 
// 		if( fp )
// 		{
// 			// output the triangles
// 			fprintf( fp, "f %d %d %d\n", VertexIndex0+1, VertexIndex1+1, VertexIndex2+1 );
// 		}
// 	}
// 	
// 	if( fp )
// 	{
// 		fclose( fp );		
// 		std::cout<<"#Saving into: "<< fname<<"\n"; 
// 	}
// // 	ReverseOrientation();
// // 	FlipVertical( g_Origin.y / 2 );
// // 	Translate( g_Origin.x, 0 );
// }


//## added by 09/03/2003

// polygon evolution
void		CPolygon::PolygonEvolution(double ratio, int iternum, BOOL bRestrained, double fRestrainedRatio, BOOL bReverse)
{
	if( NumVertex()<2 )
		return ;

	CPolygon *pOriginalPly = this->Clone();

	double sign = 1.0f;
	if( bReverse ) 
		sign = -1.0f;

	for( int iter=0; iter<iternum; iter++ )
	{
		CPolygon *pClonePly = this->Clone();
		int num = NumVertex();
		bool closed = this->GetClosed();

		for( int i=0; i<num; i++ )
		{
			// get the current vertex
			CVertex *pVert = this->GetVertex(i);
			double x = pVert->x;
			double y = pVert->y;

			// omit the end points of non-closed polygon
			if( !closed && (i==0 || i==num-1) )
				continue;

			CVertex *pPrev = pClonePly->GetVertex( (i+num-1)%num );
			CVertex *pNext = pClonePly->GetVertex( (i+1)%num );

			double dist1 = CGDIUtils::Distance(*pPrev, *pVert);
			double dist2 = CGDIUtils::Distance(*pNext, *pVert);
			double gamma = dist2/(dist1+dist2);
			pVert->x = (1.0f-sign*ratio)*x + sign*ratio*( gamma * pPrev->x + (1.0f - gamma) * pNext->x);
			pVert->y = (1.0f-sign*ratio)*y + sign*ratio*( gamma * pPrev->y + (1.0f - gamma) * pNext->y);

			if( bRestrained )
			{
				pVert->x += fRestrainedRatio * ( pOriginalPly->GetVertex(i)->x - x );
				pVert->y += fRestrainedRatio * ( pOriginalPly->GetVertex(i)->y - y );
			}
		}

		delete pClonePly;
	}

	delete pOriginalPly;

	ComputeHandles();
}

// perform Laplacian smoothing operator
void		CPolygon::SmoothLaplacian(double ratio, int iternum)
{
	if( NumVertex()<2 )
		return ;

	for( int iter=0; iter<iternum; iter++ )
	{
		CPolygon *pClonePly = this->Clone();
		int num = NumVertex();
		bool closed = this->GetClosed();

		for( int i=0; i<num; i++ )
		{
			// get the current vertex
			CVertex *pVert = this->GetVertex(i);

			// omit the end points of non-closed polygon
			if( !closed && (i==0 || i==num-1) )
				continue;

			CVertex *pPrev = pClonePly->GetVertex( (i+num-1)%num );
			CVertex *pNext = pClonePly->GetVertex( (i+1)%num );

			pVert->x = (1.0f-ratio)*pVert->x + ratio*(pPrev->x + pNext->x)/2.0f;
			pVert->y = (1.0f-ratio)*pVert->y + ratio*(pPrev->y + pNext->y)/2.0f;
		}

		delete pClonePly;
	}

	ComputeHandles();
}

// 4-point interpolation subdivision
void		CPolygon::FourPointSubdivision(double ratio, int iternum)
{
	if( NumVertex()<2 )
		return ;

	for( int iter=0; iter<iternum; iter++ )
	{
		CPolygon *pClonePly = this->Clone();
		bool closed = this->GetClosed();
		int num = NumVertex();

		Clear();

		for( int i=0; i<num; i++ )
		{
			CVertex *pCurr = pClonePly->GetVertex( i%num );

			// add the type 1 vertex
			AddVertex( pCurr->x, pCurr->y );

			// add the type 2 vertex
			if( !closed && i==num-1 )
				continue;

			CVertex *pNext = pClonePly->GetVertex( (i+1)%num );
			
			CVertex *pCurrPrev, *pNextNext;
			pCurrPrev = pClonePly->GetVertex( (i+num-1)%num );
			pNextNext = pClonePly->GetVertex( (i+2)%num );

			if( !closed )
			{
				if( i==0 )
				{
					pCurrPrev = pCurr;
				}
				if( i== num-2 )
				{
					pNextNext = pNext;
				}
			}


			double x = (1.0f+ratio)*(pCurr->x+pNext->x)/2.0f - ratio*(pCurrPrev->x + pNextNext->x) /2.0f;
			double y = (1.0f+ratio)*(pCurr->y+pNext->y)/2.0f - ratio*(pCurrPrev->y + pNextNext->y) /2.0f;
			AddVertex(x, y);
		}

		SetClosed(closed);

		delete pClonePly;
	}

	ComputeHandles();
}


// polygon simplification
void		CPolygon::Simplification(BOOL abs_num, int rm_num, double rm_ratio)
{
	int vert_num = NumVertex();

	// calculate the number of removed vertices
	int del_num = 0;
	if( abs_num )
	{
		del_num = rm_num;
	}
	else
	{
		del_num = (int)(vert_num * rm_ratio) ;
	}

	if( del_num < 0 )
		del_num = 0;
	if( del_num > vert_num-3 )
		del_num = vert_num - 3;

	bool closed = this->GetClosed();
	while( del_num >  0 )
	{
		// number of the current polygon
		vert_num = NumVertex();
		if( vert_num <=3 ) 
			break;

		// calculate the weights of vertices
		std::vector<double>  weights;
		for( int i=0; i<vert_num; i++ )
		{
			CVertex *pVert = this->GetVertex( i );

			if( !closed && (i==0 || i==vert_num-1) )
			{
				weights.push_back( 10000.0f );	// large enough weight for endponits of non-closed polygon
				continue;
			}

			CVertex *pPrev = GetVertex( (i+vert_num-1)%vert_num );
			CVertex *pNext = GetVertex( (i+1)%vert_num );

			double dist1 = CGDIUtils::Distance(*pPrev, *pVert);
			double dist2 = CGDIUtils::Distance(*pNext, *pVert);
			double dist3 = CGDIUtils::Distance(*pNext, *pPrev);
			double wt = pow( (dist1+dist2)/dist3-1.0f, 2 );

			weights.push_back( wt );
		}

		// find the minimum weight
		double minwt = 100000.0;
		int minidx = -1;
		for( int i=0; i<vert_num; i++ )
		{
			if( minwt > weights[i] )
			{
				minwt = weights[i];
				minidx = i;
			}
		}

		assert(minidx>=0);
		// remove the vertex
		this->RemoveAt(minidx);
		del_num--;
	}

	ComputeHandles();
}
//## e.o.m. by 09/03/2003


void CPolygon::DrawInGL( CSize window_size, float fGLViewWidth, float fGLViewHeight, bool bDrawCurve, bool bDrawVertex,bool bDrawNormal,CPseudoColorRGB &PsdC,Vector2 Origin/*=Vector2(0,0)*/ )
{

	int num = NumVertex();
	if( num == 0 ) 		return;

	GLubyte PsdColor[3]= {255, 255, 255};
	PsdC.SetPCValueRange(0.0, 1.0); 
	float abs_mean,abs_max;
	abs_max = num;

	glPushAttrib(GL_ALL_ATTRIB_BITS);
	glEnable(GL_LINE_SMOOTH);
	glDisable(GL_BLEND);
	glDisable(GL_TEXTURE_2D);
	glDisable(GL_LIGHTING);
	glDisable(GL_CULL_FACE);
	glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
	glLineWidth(5.0);
	glPushMatrix();
	float sz1[2] ={window_size.cx*0.5,window_size.cy*0.5};
	float sz2[2] ={2.0*fGLViewWidth/window_size.cx, 2.0*fGLViewHeight/window_size.cy};
	if(bDrawCurve){
		glColor3f(1.0,0.2,0.1);
		glBegin(GL_LINE_STRIP);
		for( int i=0; i<num; i++ ){
			CVertex *pV = GetVertex( i );
			glVertex3f( (pV->x+Origin.x-sz1[0])*sz2[0], ( sz1[1]- (pV->y+Origin.y) )*sz2[1], 0.0);
		}
		glEnd();
	}
	if(bDrawVertex){
		glPointSize(4.5f);
		glBegin(GL_POINTS);
		glDisable(GL_BLEND);
		for( int i=0; i<num; i++ ){
			abs_mean = i;
			PsdC.GetPC(PsdColor, abs_mean/abs_max);
			::glColor3ubv(PsdColor);
			CVertex *pV = GetVertex( i );
			glVertex3f( (pV->x+Origin.x-sz1[0])*sz2[0], ( sz1[1]- (pV->y+Origin.y) )*sz2[1], 0.0);
		}
		glEnd();
	}
	if(bDrawNormal){
		glColor3f(0.73,0.65,0.1);
		glLineWidth(1.5f);
		glBegin(GL_LINES);
		for( int i=0; i<num; i++ ){
			CVertex *pV = GetVertex(i);
			glVertex3f( (pV->x+Origin.x-sz1[0])*sz2[0], ( sz1[1]- (pV->y+Origin.y) )*sz2[1], 0.0);
			glVertex3f( (pV->x+Origin.x+Normal[i].x*20.0-sz1[0])*sz2[0], (sz1[1]-((pV->y+Origin.y)+Normal[i].y*20.0))*sz2[1], 0.0);
		}
		glEnd();
	}
	glPopMatrix();
	glPopAttrib();
}

void CPolygon::VertexNormal()
{
	int NP= NumVertex();
	if(NP<=1) return;
	Normal.clear();	Normal.resize(NP);
	CVertex *pV0 = GetVertex(0);
	CVertex *pV1 = GetVertex(1);
	Normal[0] = Vector2(-(pV1->y - pV0->y) ,pV1->x - pV0->x);

	for (int i=1; i<NP-1; ++i){
		pV0 = GetVertex(i-1);		pV1 = GetVertex(i+1);
		Normal[i] = Vector2(-(pV1->y - pV0->y) ,pV1->x - pV0->x);
	}
	pV0 = GetVertex(NP-2);		pV1 = GetVertex(NP-1);
	Normal[NP-1] = Vector2(-(pV1->y - pV0->y) ,pV1->x - pV0->x);

	for (int i=0; i<NP; ++i)		Normal[i].normalize();
}

void CPolygon::DrawNormal(CDC *pDC)
{
	int NP= NumVertex();
	for (int i=0; i<NP; ++i){
		CVertex *pV = GetVertex(i);
		pDC->MoveTo( (int)pV->x, (int)pV->y );
		pDC->LineTo( (int)(pV->x+Normal[i].x*20.0), (int)(pV->y+Normal[i].y*20.0));
	}
}